package com.king.collect;

import com.google.common.collect.Range;
import com.google.common.primitives.Ints;

/**
 * 在Guava中新增了一个新的类型Range，从名字就可以了解到，这个是和区间有关的数据结构。从Google官方文档可以得到定义：
 * Range定义了连续跨度的范围边界，这个连续跨度是一个可以比较的类型(Comparable type)。比如1到100之间的整型数据。
 *
 * 如果区间两边都存在范围，在这种情况下，区间右边的数不可能比区间左边的数小。在极端情况下，区间两边的数是相等的，但前提
 * 条件是最少有一个边界是闭集的，否则是不成立的。比如：
 *　[a..a] : 里面只有一个数a；
 *　[a..a); (a..a] : 空的区间范围，但是是有效的；
 *　(a..a) : 这种情况是无效的，构造这样的Range将会抛出异常。
 *　在使用Range时需要注意：在构造区间时，尽量使用不可改变的类型。如果你需要使用可变的类型，在区间类型构造完成的情况下，请不要改变区间两边的数。
 */
public class RangeTest {

    public static void main(String [] args) {
        testRange();
        testContains();
        testQuery();
        testEncloses();
        testConnected();
        testIntersection();
        testSpan();
    }

    public static void testRange() {
        System.out.println("open:"+ Range.open("ab", "cd").contains("bd"));
        System.out.println("closed:"+ Range.closed(1, 10));
        System.out.println("closedOpen:"+ Range.closedOpen(1, 10));
        System.out.println("openClosed:"+ Range.openClosed(1, 10));    
        System.out.println("greaterThan:"+ Range.greaterThan(10));
        System.out.println("atLeast:"+ Range.atLeast(10));
        System.out.println("lessThan:"+ Range.lessThan(10));
        System.out.println("atMost:"+ Range.atMost(10));
        System.out.println("all:"+ Range.all());
        System.out.println("closed:"+Range.closed(10, 10));
        System.out.println("closedOpen:"+Range.closedOpen(10, 10));
        // 会抛出异常
        // System.out.println("open:"+Range.open(10, 10));
    }

    /**
     * contains：判断值是否在当前Range内
     */
    public static void testContains() {
        System.out.println(Range.closed(1, 3).contains(2));
        System.out.println(Range.closed(1, 3).contains(4));
        System.out.println(Range.lessThan(5).contains(5));
        System.out.println(Range.closed(1, 4).containsAll(Ints.asList(1, 2, 3)));
    }

    /**
     * Endpoint相关查询方法
     */
    public static void testQuery() {
        System.out.println("hasLowerBound:"+Range.closedOpen(4, 4).hasLowerBound());
        System.out.println("hasUpperBound:"+Range.closedOpen(4, 4).hasUpperBound());
        System.out.println(Range.closedOpen(4, 4).isEmpty());
        System.out.println(Range.openClosed(4, 4).isEmpty());
        System.out.println(Range.closed(4, 4).isEmpty());
        // Range.open throws IllegalArgumentException
        //System.out.println(Range.open(4, 4).isEmpty());

        System.out.println(Range.closed(3, 10).lowerEndpoint());
        System.out.println(Range.open(3, 10).lowerEndpoint());
        System.out.println(Range.closed(3, 10).upperEndpoint());
        System.out.println(Range.open(3, 10).upperEndpoint());
        System.out.println(Range.closed(3, 10).lowerBoundType());
        System.out.println(Range.open(3, 10).upperBoundType());
    }

    /**
     * encloses方法：encloses(Range range)中的range是否包含在需要比较的range中
     */
    public static void testEncloses() {
        Range<Integer> rangeBase=Range.open(1, 4);
        Range<Integer> rangeClose=Range.closed(2, 3);
        Range<Integer> rangeCloseOpen=Range.closedOpen(2, 4);
        Range<Integer> rangeCloseOther=Range.closedOpen(2, 5);
        System.out.println("rangeBase: "+rangeBase+" Enclose:"+rangeBase.encloses(rangeClose)+" rangeClose:"+rangeClose);
        System.out.println("rangeBase: "+rangeBase+" Enclose:"+rangeBase.encloses(rangeCloseOpen)+" rangeClose:"+rangeCloseOpen);
        System.out.println("rangeBase: "+rangeBase+" Enclose:"+rangeBase.encloses(rangeCloseOther)+" rangeClose:"+rangeCloseOther);
    }

    /**
     * isConnected：range是否可连接上
     */
    public static void testConnected() {
        System.out.println(Range.closed(3, 5).isConnected(Range.open(5, 10)));
        System.out.println(Range.closed(0, 9).isConnected(Range.closed(3, 4)));
        System.out.println(Range.closed(0, 5).isConnected(Range.closed(3, 9)));
        System.out.println(Range.open(3, 5).isConnected(Range.open(5, 10)));
        System.out.println(Range.closed(1, 5).isConnected(Range.closed(6, 10)));
    }

    /**
     * intersection：如果两个range相连时，返回最大交集，如果不相连时，直接抛出异常
     */
    public static void testIntersection() {
        System.out.println(Range.closed(3, 5).intersection(Range.open(5, 10)));
        System.out.println(Range.closed(0, 9).intersection(Range.closed(3, 4)));
        System.out.println(Range.closed(0, 5).intersection(Range.closed(3, 9)));
        System.out.println(Range.open(3, 5).intersection(Range.open(5, 10)));
        System.out.println(Range.closed(1, 5).intersection(Range.closed(6, 10)));
    }

    /**
     * span：获取两个range的并集，如果两个range是相连的，则是其最小range
     */
    public static void testSpan() {
        System.out.println(Range.closed(3, 5).span(Range.open(5, 10)));
        System.out.println(Range.closed(0, 9).span(Range.closed(3, 4)));
        System.out.println(Range.closed(0, 5).span(Range.closed(3, 9)));
        System.out.println(Range.open(3, 5).span(Range.open(5, 10)));
        System.out.println(Range.closed(1, 5).span(Range.closed(6, 10)));
        System.out.println(Range.closed(1, 5).span(Range.closed(7, 10)));
    }
}